<?php

namespace app\common\library\Helper;

use Carbon\Carbon;

class DateTime
{
    /******************************日******************************/
    /**
     * 今日Y-m-d
     * @return string
     */
    public static function nowDate(): string
    {
        return Carbon::now()->toDateString();
    }

    /**
     * 当前时间Y-m-d H:i:s
     * @return string
     */
    public static function now(): string
    {
        return Carbon::now()->toDateTimeString();
    }

    /**
     * 今日开始时间
     * @return string
     */
    public static function todayStart(): string
    {
        return Carbon::today()->toDateTimeString();
    }

    /**
     * 今日结束时间
     * @return string
     */
    public static function todayEnd(): string
    {
        return Carbon::today()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 昨日Y-m-d
     * @return string
     */
    public static function yesterdayDate(): string
    {
        return Carbon::yesterday()->toDateString();
    }

    /**
     * 昨日开始时间
     * @return string
     */
    public static function yesterdayStart(): string
    {
        return Carbon::yesterday()->toDateTimeString();
    }

    /**
     * 昨日结束时间
     * @return string
     */
    public static function yesterdayEnd(): string
    {
        return Carbon::yesterday()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 明日Y-m-d
     * @return string
     */
    public static function tomorrowDate(): string
    {
        return Carbon::tomorrow()->toDateString();
    }

    /**
     * 明日开始时间
     * @return string
     */
    public static function tomorrowStart(): string
    {
        return Carbon::tomorrow()->toDateTimeString();
    }

    /**
     * 明日结束时间
     * @return string
     */
    public static function tomorrowEnd(): string
    {
        return Carbon::tomorrow()->addSeconds(86399)->toDateTimeString();
    }

    /******************************周******************************/

    /**
     * 本周开始时间
     * @return string
     */
    public static function weekStart(): string
    {
        return Carbon::now()->startOfWeek()->toDateTimeString();
    }

    /**
     * 本周结束时间
     * @return string
     */
    public static function weekEnd(): string
    {
        return Carbon::now()->endOfWeek()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 上周开始时间
     * @return string
     */
    public static function lastWeekStart(): string
    {
        return Carbon::now()->subWeek()->startOfWeek()->toDateTimeString();
    }

    /**
     * 上周结束时间
     * @return string
     */
    public static function lastWeekEnd(): string
    {
        return Carbon::now()->subWeek()->endOfWeek()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 下周开始时间
     * @return string
     */
    public static function nextWeekStart(): string
    {
        return Carbon::now()->addWeek()->startOfWeek()->toDateTimeString();
    }

    /**
     * 下周结束时间
     * @return string
     */
    public static function nextWeekEnd(): string
    {
        return Carbon::now()->addWeek()->endOfWeek()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 返回中文星期
     * @param string $week
     * @return array
     */
    public static function chineseWeek(string $week): array
    {
        $weekArr     = explode(',', $week);
        $chineseWeek = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
        return array_map(function ($item) use ($chineseWeek) {
            return $chineseWeek[$item];
        }, $weekArr);
    }

    /******************************月******************************/

    /**
     * 本月日期
     * @return string
     */
    public static function monthDate(): string
    {
        $now = Carbon::now();
        return $now->year . '-' . $now->month;
    }

    /**
     * 本月第一天
     * @return string
     */
    public static function monthStart(): string
    {
        return Carbon::now()->startOfMonth()->toDateTimeString();
    }

    /**
     * 本月最后一天
     * @return string
     */
    public static function monthEnd(): string
    {
        return Carbon::now()->endOfMonth()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 上月第一天
     * @return string
     */
    public static function lastMonthStart(): string
    {
        return Carbon::now()->subMonth()->startOfMonth()->toDateTimeString();
    }

    /**
     * 上月最后一天
     * @return string
     */
    public static function lastMonthEnd(): string
    {
        return Carbon::now()->subMonth()->endOfMonth()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 下月第一天
     * @return string
     */
    public static function nextMonthStart(): string
    {
        return Carbon::now()->addMonth()->startOfMonth()->toDateTimeString();
    }

    /**
     * 下月最后一天
     * @return string
     */
    public static function nextMonthEnd(): string
    {
        return Carbon::now()->addMonth()->endOfMonth()->addSeconds(86399)->toDateTimeString();
    }

    /******************************年******************************/

    /**
     * 本年第一天
     * @return string
     */
    public static function yearStart(): string
    {
        return Carbon::now()->startOfYear()->toDateTimeString();
    }

    /**
     * 本年最后一天
     * @return string
     */
    public static function yearEnd(): string
    {
        return Carbon::now()->endOfYear()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 去年第一天
     * @return string
     */
    public static function lastYearStart(): string
    {
        return Carbon::now()->subYear()->startOfYear()->toDateTimeString();
    }

    /**
     * 去年最后一天
     * @return string
     */
    public static function lastYearEnd(): string
    {
        return Carbon::now()->subYear()->endOfYear()->addSeconds(86399)->toDateTimeString();
    }

    /**
     * 明年第一天
     * @return string
     */
    public static function nextYearStart(): string
    {
        return Carbon::now()->addYear()->startOfYear()->toDateTimeString();
    }

    /**
     * 明年最后一天
     * @return string
     */
    public static function nextYearEnd(): string
    {
        return Carbon::now()->addYear()->endOfYear()->addSeconds(86399)->toDateTimeString();
    }

    /******************************范围******************************/

    /**
     * 今日范围
     * @return array
     */
    public static function todayRange(): array
    {
        return [
            self::todayStart(),
            self::todayEnd(),
        ];
    }

    /**
     * 昨日范围
     * @return array
     */
    public static function yesterdayRange(): array
    {
        return [
            self::yesterdayStart(),
            self::yesterdayEnd(),
        ];
    }

    /**
     * 明日范围
     * @return array
     */
    public static function tomorrowRange(): array
    {
        return [
            self::tomorrowStart(),
            self::tomorrowEnd(),
        ];
    }

    /**
     * 本周范围
     * @return array
     */
    public static function weekRange(): array
    {
        return [
            self::weekStart(),
            self::weekEnd(),
        ];
    }

    /**
     * 上周范围
     * @return array
     */
    public static function lastWeekRange(): array
    {
        return [
            self::lastWeekStart(),
            self::lastWeekEnd(),
        ];
    }

    /**
     * 下周范围
     * @return array
     */
    public static function nextWeekRange(): array
    {
        return [
            self::nextWeekStart(),
            self::nextWeekEnd(),
        ];
    }

    /**
     * 本月范围
     * @return array
     */
    public static function monthRange(): array
    {
        return [
            self::monthStart(),
            self::monthEnd(),
        ];
    }

    /**
     * 上月范围
     * @return array
     */
    public static function lastMonthRange(): array
    {
        return [
            self::lastMonthStart(),
            self::lastMonthEnd(),
        ];
    }

    /**
     * 下月范围
     * @return array
     */
    public static function nextMonthRange(): array
    {
        return [
            self::nextMonthStart(),
            self::nextMonthEnd(),
        ];
    }

    /**
     * 本年范围
     * @return array
     */
    public static function yearRange(): array
    {
        return [
            self::yearStart(),
            self::yearEnd(),
        ];
    }

    /**
     * 去年范围
     * @return array
     */
    public static function lastYearRange(): array
    {
        return [
            self::lastYearStart(),
            self::lastYearEnd(),
        ];
    }

    /**
     * 明年范围
     * @return array
     */
    public static function nextYearRange(): array
    {
        return [
            self::nextYearStart(),
            self::nextYearEnd(),
        ];
    }

    /**
     * 根据传入日期获取日范围
     * @param string $date
     * @return array
     */
    public static function rangeDayByDate(string $date): array
    {
        return [Carbon::parse($date)->startOfDay(), Carbon::parse($date)->endOfDay()];
    }

    /**
     * 根据传入日期获取月范围
     * @param string $date
     * @return array
     */
    public static function rangeMonthByDate(string $date): array
    {
        return [Carbon::parse($date)->startOfMonth(), Carbon::parse($date)->endOfMonth()];
    }

    /**
     * 根据传入日期获取年范围
     * @param string $date
     * @return array
     */
    public static function rangeYearByDate(string $date): array
    {
        return [Carbon::parse($date)->startOfYear(), Carbon::parse($date)->endOfYear()];
    }

    /******************************计算******************************/

    /**
     * 今日前后增加天数
     * @param int $days
     * @return string
     */
    public static function todayAddDays(int $days): string
    {
        return Carbon::today()->addDays($days)->toDateTimeString();
    }

    /**
     * 当前前后增加秒数
     * @param int $seconds
     * @return string
     */
    public static function nowAddSeconds(int $seconds): string
    {
        return Carbon::now()->addSeconds($seconds)->toDateTimeString();
    }

    /**
     * 间隔天数
     * @param string $start
     * @param string $end
     * @return int
     */
    public static function intervalDays(string $start, string $end): int
    {
        return Carbon::parse($end)->diffInDays(Carbon::parse($start));
    }

    /**
     * 间隔小时
     * @param string $start
     * @param string $end
     * @return int
     */
    public static function intervalHours(string $start, string $end): int
    {
        return Carbon::parse($end)->diffInHours(Carbon::parse($start));
    }

    /**
     * 间隔分钟
     * @param string $start
     * @param string $end
     * @return int
     */
    public static function intervalMinutes(string $start, string $end): int
    {
        return Carbon::parse($end)->diffInMinutes(Carbon::parse($start));
    }

    /**
     * 间隔秒数
     * @param string $start
     * @param string $end
     * @return int
     */
    public static function intervalSeconds(string $start, string $end): int
    {
        return Carbon::parse($end)->diffInSeconds(Carbon::parse($start));
    }

    /**
     * 根据传入日期增加天数
     * @param string $date
     * @param int $days
     * @return string
     */
    public static function addDaysByDate(string $date, int $days): string
    {
        return Carbon::parse($date)->addSeconds(-1)->addDays($days)->toDateTimeString();
    }

    /**
     * 根据传入日期重新格式化日期
     * @param string $date
     * @param string $format
     * @return string
     */
    public static function newDateFormatByDate(string $date, string $format = 'Y-m'): string
    {
        return Carbon::parse($date)->format($format);
    }

    /******************************判断******************************/

    /**
     * 是否是今天
     * @param string $date
     * @return bool
     */
    public static function isToday(string $date): bool
    {
        return Carbon::parse($date)->isToday();
    }

    /**
     * 是否是昨天
     * @param string $date
     * @return bool
     */
    public static function isYesterday(string $date): bool
    {
        return Carbon::parse($date)->isYesterday();
    }

    /**
     * 是否是明天
     * @param string $date
     * @return bool
     */
    public static function isTomorrow(string $date): bool
    {
        return Carbon::parse($date)->isTomorrow();
    }

    /**
     * 是否在某个时间段内
     */
    public static function isBetween(string $date, string $start, string $end): bool
    {
        return Carbon::parse($date)->between($start, $end);
    }

    /******************************其它******************************/

    /**
     * 转时间戳
     * @param string $method
     * @param ...$arg
     * @return ?array
     */
    public static function toTimestamp(string $method, ...$arg): ?array
    {
        $res = self::{$method}(...$arg);
        if (is_string($res)) {
            return strtotime($res);
        } elseif (is_array($res)) {
            return [strtotime($res[0]), strtotime($res[1])];
        } else {
            return $res;
        }
    }

    /**
     * 日期列表
     * @param string $start
     * @param string $end
     * @param string $format
     * @return array
     */
    public static function dateList(string $start, string $end, string $format = 'Y-m-d'): array
    {
        $start = Carbon::parse($start);
        $end   = Carbon::parse($end);
        $list  = [];
        while ($start->lte($end)) {
            $list[] = $start->format($format);
            $start->addDay();
        }
        return $list;
    }

}